import { injectable } from "tsyringe";
@injectable()
export class QueryBuilder {
    private aliasMap: Map<string, string> = new Map()
    parent: QueryBuilder;
    toSql(_sql: string, _parameters: any = {}): [string, any[]] {
        let i: number = 0;
        const parameters: any = {}
        const toSql = (sql: string): string => {
            return sql.replace(/(#\w+)/g, (string, replaceValue) => {
                const [, name] = string.split('#')
                const subSql = this.get(name);
                if (subSql) return toSql(subSql)
                return string;
            })
        }
        const sql: string = toSql(_sql).replace(/(:\w+)/g, (string) => {
            const [, name] = string.split(':')
            if (Reflect.has(parameters, name)) {
                return `$${Reflect.get(parameters, name)}`
            }
            i += 1;
            Reflect.set(parameters, name, i)
            return `$${i}`
        })
        const parmas: any[] = new Array(Object.keys(parameters).length)
        Object.keys(parameters).map(key => {
            const index = parameters[key]
            if (Reflect.has(_parameters, key)) {
                Reflect.set(parmas, index - 1, Reflect.get(_parameters, key))
            } else {
                throw new Error(`mission ${key} in parameters`)
            }
        })
        return [sql, parmas]
    }
    set(alias: string, sql: string) {
        this.aliasMap.set(alias, sql)
    }
    get(name: string): string | undefined {
        if (this.aliasMap.has(name)) return this.aliasMap.get(name)
        if (this.parent) return this.parent.get(name)
        return undefined;
    }
    create() {
        const qb = new QueryBuilder()
        qb.parent = this;
        return qb;
    }
}
